package cqrtplm.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hustcad.plm.basic.vo.cad.CadDownloadFileVO;
import com.hustcad.plm.pdm.basedrule.dto.TyplmBaseRuleBoundedObjDTO;
import com.hustcad.plm.pdm.basedrule.service.TyplmBasedRuleService;
import com.hustcad.plm.pdm.code.model.dto.codemanagement.TyplmSegmentCodeConditionDTO;
import com.hustcad.plm.pdm.code.model.vo.codemanagement.segmentcode.TyplmSegmentCodeRuleVO;
import com.hustcad.plm.pdm.code.service.codemanagement.TyplmSegmentCodeService;
import com.hustcad.plm.pdm.container.model.entity.Container;
import com.hustcad.plm.pdm.container.model.vo.ContainerCommonQueryVO;
import com.hustcad.plm.pdm.container.service.ContainerService;
import com.hustcad.plm.pdm.doc.dto.CreateDocInputDTO;
import com.hustcad.plm.pdm.doc.vo.DocumentVO;
import com.hustcad.plm.pdm.ec.module.dto.AffectedObjectDTO;
import com.hustcad.plm.pdm.ec.module.dto.TyplmChangeIssueDTO;
import com.hustcad.plm.pdm.ec.module.dto.TyplmChangeIssueDetailDTO;
import com.hustcad.plm.pdm.ec.service.TyplmChangeIssueService;
import com.hustcad.plm.pdm.ec.service.TyplmIssueAgainstDataService;
import com.hustcad.plm.pdm.file.model.dto.BatchUploadDTO;
import com.hustcad.plm.pdm.file.model.dto.ContentUploadDTO;
import com.hustcad.plm.pdm.file.model.dto.DownloadFileDTO;
import com.hustcad.plm.pdm.file.model.dto.FileGroupDTO;
import com.hustcad.plm.pdm.file.model.vo.DownLoadFile.DownLoadFileVO;
import com.hustcad.plm.pdm.file.service.TyplmFileHandleService;
import com.hustcad.plm.pdm.file.service.upload.TyplmFileTransferService;
import com.hustcad.plm.pdm.file.util.TyplmDownloadToolUtil;
import com.hustcad.plm.pdm.filevault.model.vo.FileDataVO;
import com.hustcad.plm.pdm.filevault.service.TyplmContentDataService;
import com.hustcad.plm.pdm.filevault.service.TyplmEncryptService;
import com.hustcad.plm.pdm.flowbusiness.model.entity.FlowObject;
import com.hustcad.plm.pdm.flowbusiness.model.entity.WorkFlowObjectPackage;
import com.hustcad.plm.pdm.flowbusiness.service.TyplmWorkFlowObjectPackageService;
import com.hustcad.plm.pdm.folder.model.vo.SubfolderWebVO;
import com.hustcad.plm.pdm.folder.service.TyplmSubFolderLinkService;
import com.hustcad.plm.pdm.iba.service.TyplmAttributeValueService;
import com.hustcad.plm.pdm.security.util.AESUtil;
import com.hustcad.plm.pdm.type.service.TyplmTypeService;
import com.hustcad.plm.pdm.user.model.dto.PdmUserDTO;
import com.hustcad.plm.pdm.user.service.TyplmUserService;
import com.hustcad.plm.pdm.workflow.model.entity.UserTaskDTO;
import com.hustcad.plm.pdm.workflow.model.entity.WorkFlow;
import com.hustcad.plm.pdm.workflow.model.entity.WorkFlowContainerView;
import com.hustcad.plm.pdm.workflow.service.TyplmWorkFlowContainerService;
import com.hustcad.plm.pdm.workflow.service.TyplmWorkFlowProcessService;
import com.hustcad.plm.rpm.model.dto.issue.CreatIssueLinkDTO;
import com.ty.basic.constant.TableTypeConstrant;
import com.ty.basic.entity.IdentifierEntity;
import com.ty.basic.entity.org.UserDO;
import com.ty.basic.service.snow.SnowflakeIdComponent;
import com.ty.basic.session.TyAccountContext;
import com.ty.basic.vo.AttributeVO;
import cqrtplm.common.CommonService;
import cqrtplm.constant.RTErrorCodeEnum;
import cqrtplm.constant.RTPlmConstant;
import cqrtplm.dto.IssusLinkPathDTO;
import cqrtplm.dto.PreventErrorCorrectionDTO;
import cqrtplm.dto.ProblemItemDTO;
import cqrtplm.dto.StartProblemItemTaskDTO;
import cqrtplm.entity.PreventErrorCorrectionDO;
import cqrtplm.mapper.PreventErrorCorrectionMapper;
import cqrtplm.mapper.RTContainerAndFolderMapper;
import cqrtplm.mapper.RTFormTemplateMapper;
import cqrtplm.service.FlowControlService;
import cqrtplm.service.HistoryDataImportService;
import cqrtplm.service.PreventErrorCorrectionService;
import cqrtplm.service.RTContainerAndFolderService;
import cqrtplm.service.RTDocService;
import cqrtplm.util.Base64ToMultipartFileUtil;
import cqrtplm.util.ExcelImageUtils;
import cqrtplm.util.PageDtoUtil;
import cqrtplm.util.ProjectCodeGenerator;
import cqrtplm.util.RTFileUtil;
import cqrtplm.vo.IssusImagePathDTO;
import cqrtplm.vo.PreventErrorCorrectionVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.util.UriComponentsBuilder;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.ty.basic.utils.excel.converter.ExcelToList.getWorkbook;


@Service
@Slf4j
public class PreventErrorCorrectionServiceImpl implements PreventErrorCorrectionService {
    private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
    @Resource
    private PreventErrorCorrectionMapper preventErrorCorrectionMapper;
    @Resource
    private TyplmChangeIssueService typlmChangeIssueService;
    @Resource
    private RTContainerAndFolderService containerAndFolderService;
    @Resource
    private TyplmTypeService typlmTypeService;
    @Resource
    private RTContainerAndFolderMapper containerAndFolderMapper;
    @Resource
    private TyplmBasedRuleService typlmBasedRuleService;
    @Resource
    private TyplmSegmentCodeService typlmSegmentCodeService;
    @Resource
    private RTFormTemplateMapper formTemplateMapper;
    @Resource
    private SnowflakeIdComponent snowflakeIdComponent;
    @Resource
    private RTFileUtil rtFileUtil;
    @Resource
    private TyplmWorkFlowProcessService typlmWorkFlowProcessService;
    @Resource
    private TyplmWorkFlowObjectPackageService typlmWorkFlowObjectPackageService;
    @Resource
    private RTDocService docService;
    @Resource
    private TyplmIssueAgainstDataService typlmIssueAgainstDataService;
    @Resource
    private TyplmSubFolderLinkService typlmSubFolderLinkService;
    @Resource
    private TyplmWorkFlowContainerService typlmWorkFlowContainerService;
    @Resource
    private FlowControlService flowControlService;
    @Resource
    private TyplmFileHandleService fileHandleService;
    @Resource
    private ContainerService containerService;
    @Resource
    private CommonService commonService;
    @Resource
    private TyplmAttributeValueService typlmAttributeValueService;
    @Resource
    private TyplmFileTransferService typlmFileTransferService;
    @Resource
    private TyplmEncryptService typlmEncryptService;
    @Resource
    private TyplmContentDataService typlmContentDataService;
    @Resource
    private TyplmUserService typlmUserService;
    @Resource
    private HistoryDataImportService historyDataImportService;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private ProjectCodeGenerator projectCodeGenerator;


    @Value("${issue.service.url}")
    private String mainServiceUrl;
    @Value("${ipd.base.url:http://127.0.0.1:9588}")
    private String ipdUrl;



    @Override
    public PageInfo<PreventErrorCorrectionVO> getPreventErrorCorrectionList(PreventErrorCorrectionDTO dto) {
        PageHelper.startPage(Integer.parseInt(dto.getPage(), Integer.parseInt(dto.getRow())));
        List<PreventErrorCorrectionVO> list = preventErrorCorrectionMapper.selectByCondition(dto);
        return new PageInfo<>(list);
    }

    @Override
    public PageDtoUtil importPreventErrorCorrection(MultipartFile file) {
        log.info("导入预防纠错数据开始");
        List<PreventErrorCorrectionDO> originalList = getPreventErrorDataFromExl(file);
        Field[] fields = PreventErrorCorrectionDO.class.getDeclaredFields();

        List<PreventErrorCorrectionDO> list = originalList.stream()
                // 保留所有不满足“mid非空且其他字段全空”条件的对象
                .filter(obj -> {
                    // 条件1：mid为null → 直接保留（不符合排除条件）
                    if (obj.getMid() == null) {
                        return true;
                    }
                    // 条件2：mid非空时，检查是否有其他字段非空
                    try {
                        for (Field field : fields) {
                            String fieldName = field.getName();
                            // 跳过mid和uploader字段
                            if ("mid".equals(fieldName) || "uploader".equals(fieldName)) {
                                continue;
                            }
                            field.setAccessible(true);
                            Object value = field.get(obj);

                            // 判断字段值是否为有效内容（非null且非空字符串）
                            if (value != null) {
                                // 字符串类型需要额外判断是否为空串
                                if (value instanceof String) {
                                    if (!((String) value).trim().isEmpty()) {
                                        return true; // 存在有效字符串，保留对象
                                    }
                                } else {
                                    // 非字符串类型（如Date、Integer等）只要不为null即为有效
                                    return true;
                                }
                            }
                            // 若字段值为null或空字符串，继续检查下一个字段
                        }
                        // 走到这里说明：mid非空且其他字段全空 → 需要排除
                        return false;
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                        return true; // 反射异常时默认保留
                    }
                })
                .collect(Collectors.toList());
        return PageDtoUtil.getPage(list);
    }


//        if (CollUtil.isNotEmpty(list)){
//            preventErrorCorrectionMapper.batchInsertPrevent(list);
//        }

//        log.info("导入数据成功");
//        log.info("解析预防纠错附件开始");
//        List<IssusImagePathDTO> issueImagePathDataFromExl = getIssueImagePathDataFromExl(file);
//
//        Map<String, List<IssusImagePathDTO>> integerIssusImagePathVOMap = issueImagePathDataFromExl.stream()
//                .filter(d -> d.getF_FolderId() != null && !d.getF_FolderId().isEmpty()) // 过滤F_FolderId非空的对象
//                .collect(Collectors.groupingBy(
//                        IssusImagePathDTO::getF_FolderId // 按F_FolderId分组
//                ));
//        Map<String, IssusImagePathDTO> integerIssusImagePathVOMap =
//                issueImagePathDataFromExl.stream()
//                        .filter(d -> d.getF_FolderId() != null && !d.getF_FolderId().isEmpty())
//                        .collect(Collectors.toMap(
//                                IssusImagePathDTO::getF_FolderId,
//                                d -> d
//                        ));
       // List<IssusLinkPathDTO> issusLinkPathDTOList = new ArrayList<>();

        //获取有关联的附件对象
//        if (CollUtil.isNotEmpty(integerIssusImagePathVOMap) && CollUtil.isNotEmpty(list)) {
//            // 存放最终返回给前端的文件信息列表
//            list.forEach(p -> {
//                if (ObjectUtil.isNotEmpty(integerIssusImagePathVOMap.get(p.getPhenomenonFile()))) {
//
//                    List<FileInfoDTO> fileInfoList = new ArrayList<>();
//                    List<IssusImagePathDTO> issusImagePathDTOList = integerIssusImagePathVOMap.get(
//                            p.getPhenomenonFile());
//                    if (CollUtil.isNotEmpty(issusImagePathDTOList)) {
//                        List<String> filePathList = issusImagePathDTOList.stream().map(IssusImagePathDTO::getF_FilePath)
//                                .collect(Collectors.toList());
//                        if (CollUtil.isNotEmpty(filePathList)) {
//                            //文件路径->文件
//                            Map<String, MultipartFile> fileFromFtp = historyDataImportService.getFileFromFtp(
//                                    filePathList);
//
//                            // 遍历所有文件，转换并封装成DTO
//                            for (Map.Entry<String, MultipartFile> entry : fileFromFtp.entrySet()) {
//                                String filePath = entry.getKey();
//                                MultipartFile multipartFile = entry.getValue();
//                                try {
//                                    // 跳过空文件
//                                    if (multipartFile.isEmpty()) {
//                                        continue;
//                                    }
//                                    // 获取文件名（从路径中提取或直接用MultipartFile的文件名）
//                                    String fileName = multipartFile.getOriginalFilename();
//                                    if (fileName == null || fileName.isEmpty()) {
//                                        // 若文件名为空，从文件路径末尾提取
//                                        fileName = new java.io.File(filePath).getName();
//                                    }
//                                    // 将文件转为Base64编码（前端可直接用于<img>标签的src）
//                                    byte[] fileBytes = multipartFile.getBytes();
//                                    String base64Content = "data:" + multipartFile.getContentType() + ";base64,"
//                                            + Base64.getEncoder().encodeToString(fileBytes);
//
//                                    // 封装成DTO
//                                    FileInfoDTO fileInfo = new FileInfoDTO();
//                                    fileInfo.setFilePath(filePath);
//                                    fileInfo.setFileName(fileName);
//                                    fileInfo.setFileByte(base64Content);
//                                    fileInfoList.add(fileInfo);
//
//                                } catch (IOException e) {
//                                    // 处理单个文件的异常（如日志记录），不影响其他文件
//                                    e.printStackTrace();
//                                }
//                            }
//
//                            p.setFileInfoList(fileInfoList);
//                        }
//                    }
//
//                }
//
//            });
//        }




//        Map<String, List<IssusLinkPathDTO>> stringListMap = issusLinkPathDTOList.stream().collect(
//                Collectors.groupingBy(IssusLinkPathDTO::getMid));
//
//        //插入关联关系
//        if (CollUtil.isNotEmpty(issusLinkPathDTOList)){
//            preventErrorCorrectionMapper.batchInsertPreventPath(issusLinkPathDTOList);
//        }
//
        //创建问题报告
//        UserDO user = TyAccountContext.getUser();
//        try {
//            ContainerCommonQueryVO container = containerAndFolderService.getContainerByName(RTPlmConstant.PRODUCT_CONTAINER_NAME);
//            BigInteger noticeTypeOid = typlmTypeService.getTypeOidByName("问题");
//            BigInteger containerId = new BigInteger(container.getId());
//            TyplmBaseRuleBoundedObjDTO info = this.typlmBasedRuleService.getBaseRuleBoundedObjInfo(
//                    noticeTypeOid, containerId, container.getOtype());
//            TyplmSegmentCodeConditionDTO param = new TyplmSegmentCodeConditionDTO();
//            param.setOtype(TableTypeConstrant.TY_CHANGEISSUE_OTYPE);
//            param.setRuleInfo(new IdentifierEntity(info.getSegmentCodeOid(), info.getSegmentCodeOtype()));
//            TyplmSegmentCodeRuleVO codeData = this.typlmSegmentCodeService.getSegmentFormData(param);
//            BigInteger subFolderOid = containerAndFolderMapper.getOIDByNameAndContainerOid(
//                    RTPlmConstant.PROBLEM_REPORT, containerId);
//            String formTemplateData = formTemplateMapper.queryTemplateDataByOid(info.getFormTemplateOid());
//            for (PreventErrorCorrectionDO preventErrorCorrectionDO : list) {
//                TyplmChangeIssueDTO changeIssueDTO = new TyplmChangeIssueDTO();
//                changeIssueDTO.setName(RTPlmConstant.PROBLEM_REPORT);
//                //            if (CollUtil.isNotEmpty(files)) {
//                //                changeIssueDTO.setFileList(files);
//                //            }
//                changeIssueDTO.setContaineroid(containerId);
//                changeIssueDTO.setContainerotype(container.getOtype());
//                changeIssueDTO.setSubfolderoid(subFolderOid);
//                changeIssueDTO.setTypeoid(noticeTypeOid);
//                changeIssueDTO.setCreatoroid(user.getOid());
//                changeIssueDTO.setObjectNumber(codeData.getCode());
//                changeIssueDTO.setFormtemplateoid(info.getFormTemplateOid());
//                changeIssueDTO.setFormtemplateotype(info.getFormTemplateOtype());
//
//
//
//                changeIssueDTO.setFormData(buildFormData(preventErrorCorrectionDO,formTemplateData));
//                changeIssueDTO.setIssuepriority(RTPlmConstant.NORMAL);
//                List<TyplmChangeIssueDetailDTO> changeIssue = typlmChangeIssueService.createChangeIssue(changeIssueDTO);
//                System.out.println(changeIssue);
//
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            log.error("创建问题报告失败:{}", e.getMessage());
//
//        }





    private List<PreventErrorCorrectionDO> getPreventErrorDataFromExl(MultipartFile multipartFile) {
        List<PreventErrorCorrectionDO> list = new ArrayList<>();
        InputStream inputStream = null;
        ExcelReader excelReader = null;
        Map<String,File> imageFileMap = new HashMap<>();
        try {
            // 1. 在读取Excel之前，先提取所有图片
            Workbook workbook = getWorkbook(multipartFile);
            Map<String, List<byte[]>> imageMap = ExcelImageUtils.extractAllFloatingImages(workbook);
            imageFileMap = rtFileUtil.extractImages(multipartFile);
            inputStream = multipartFile.getInputStream();
            excelReader = ExcelUtil.getReader(inputStream, 0);
            excelReader.setIgnoreEmptyRow(true);
            int rowCount = excelReader.getRowCount();
            //  读取Excel文件的起始行
            int readExcelBeginRow = 1;
            for (int i = readExcelBeginRow; i < rowCount; i++) {
                PreventErrorCorrectionDO preventErrorCorrectionDO = new PreventErrorCorrectionDO();
                preventErrorCorrectionDO.setMid(String.valueOf(snowflakeIdComponent.getInstance().nextId()));
                preventErrorCorrectionDO.setType(getExlCellValue(excelReader, 1,i));
                preventErrorCorrectionDO.setProjectNo(getExlCellValue(excelReader, 2,i));
                preventErrorCorrectionDO.setTerminalModel(getExlCellValue(excelReader, 3,i));
                preventErrorCorrectionDO.setPowerModel(getExlCellValue(excelReader, 4,i));
                preventErrorCorrectionDO.setComponentName(getExlCellValue(excelReader, 5,i));
                preventErrorCorrectionDO.setPatternCode(getExlCellValue(excelReader, 6,i));

                String occurrenceDate = getExlCellValue(excelReader, 7, i);
                // 空值或解析失败时均设为null
                preventErrorCorrectionDO.setOccurrenceDate(parseDate(occurrenceDate, sdf));

                preventErrorCorrectionDO.setOccurrenceStage(getExlCellValue(excelReader, 8,i));
                preventErrorCorrectionDO.setOccurrenceEnvironment(getExlCellValue(excelReader, 9,i));
                preventErrorCorrectionDO.setPhenomenonDescription(getExlCellValue(excelReader, 10,i));
                //TODO 11 不良现象图片

                // 处理图片列 (第11列，索引10)
                List<byte[]> images = ExcelImageUtils.getImagesByCell(
                        imageMap,
                        excelReader.getSheetNames().get(0), // 当前工作表名称
                        i,                          // 当前行
                        11                         // 图片所在列 (11列，索引10)
                );
                // 处理图片数据 - 这里可以根据需要选择处理方式
                if (!images.isEmpty()) {
                    String base64Image = ExcelImageUtils.convertToBase64(images.get(0), "png");
                    preventErrorCorrectionDO.setPhenomenonFile(base64Image);
                } else {
                    preventErrorCorrectionDO.setPhenomenonFile(null);
                }
           //     preventErrorCorrectionDO.setPhenomenonFile(getExlCellValue(excelReader, 11,i));

                preventErrorCorrectionDO.setAnalysisDescription(getExlCellValue(excelReader, 12,i));
                preventErrorCorrectionDO.setTentativeCountermeasures(getExlCellValue(excelReader, 13,i));
                preventErrorCorrectionDO.setLongCountermeasures(getExlCellValue(excelReader, 14,i));
                preventErrorCorrectionDO.setSourceImprovement(getExlCellValue(excelReader, 15,i));
                // TODO 16 对策（支持文件）
                preventErrorCorrectionDO.setCountermeasure(getExlCellValue(excelReader, 16,i));
                preventErrorCorrectionDO.setSupplier(getExlCellValue(excelReader, 17,i));
                preventErrorCorrectionDO.setProblemType(getExlCellValue(excelReader, 18,i));
                preventErrorCorrectionDO.setClosingStage(getExlCellValue(excelReader, 19,i));
                preventErrorCorrectionDO.setPersonResponsible(getExlCellValue(excelReader, 20,i));
                preventErrorCorrectionDO.setExperimentalCommissioner(getExlCellValue(excelReader, 21,i));
                preventErrorCorrectionDO.setDepartment(getExlCellValue(excelReader, 22,i));
                preventErrorCorrectionDO.setFeedbackPerson(getExlCellValue(excelReader, 23,i));
                preventErrorCorrectionDO.setImportance(getExlCellValue(excelReader, 24,i));

                // 计划日期解析
                String plannedDateStr = getExlCellValue(excelReader, 25, i);
                preventErrorCorrectionDO.setPlannedDate(parseDate(plannedDateStr, sdf));

                preventErrorCorrectionDO.setConfirmationMethod(getExlCellValue(excelReader, 26,i));
                // TODO 26 结果附件
                preventErrorCorrectionDO.setConfirmFile(getExlCellValue(excelReader, 27,i));
                preventErrorCorrectionDO.setProgressConfirmation(getExlCellValue(excelReader, 28,i));
                preventErrorCorrectionDO.setIsClose(getExlCellValue(excelReader, 29,i));

                // 确认日期解析
                String confirmDateStr = getExlCellValue(excelReader, 30, i);
                preventErrorCorrectionDO.setConfirmDate(parseDate(confirmDateStr, sdf));

                preventErrorCorrectionDO.setConfirmationPerson(getExlCellValue(excelReader, 31,i));
                preventErrorCorrectionDO.setRemark(getExlCellValue(excelReader, 32,i));
                list.add(preventErrorCorrectionDO);
            }
            return list;
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            try {
                if (excelReader != null)
                    excelReader.close();
                if (inputStream != null)
                    inputStream.close();
            } catch (Exception e) {
                log.error("Exception occurred while closing stream: {}", ExceptionUtil.stacktraceToString(e));
            }
        }
        return list;
    }

    private List<IssusImagePathDTO> getIssueImagePathDataFromExl(MultipartFile multipartFile) {

        List<IssusImagePathDTO> list = new ArrayList<>();
        InputStream inputStream = null;
        ExcelReader excelReader = null;
        Map<String,File> imageFileMap = new HashMap<>();
        try {
            imageFileMap = rtFileUtil.extractImages(multipartFile);
            inputStream = multipartFile.getInputStream();
            excelReader = ExcelUtil.getReader(inputStream, 1);
            excelReader.setIgnoreEmptyRow(true);
            int rowCount = excelReader.getRowCount();
            //  读取Excel文件的起始行
            int readExcelBeginRow = 1;
            for (int i = readExcelBeginRow; i < rowCount; i++) {
                IssusImagePathDTO issusImagePathVO = new IssusImagePathDTO();
                issusImagePathVO.setId(i);
                issusImagePathVO.setF_Id(getExlCellValue(excelReader, 0,i));
                issusImagePathVO.setF_FolderId(getExlCellValue(excelReader, 1,i));
                issusImagePathVO.setF_FileName(getExlCellValue(excelReader, 2,i));
                issusImagePathVO.setF_FilePath(getExlCellValue(excelReader, 3,i));
                issusImagePathVO.setF_FileSize(getExlCellValue(excelReader, 4,i));
                issusImagePathVO.setF_FileExtensions(getExlCellValue(excelReader, 5,i));
                issusImagePathVO.setF_FileType(getExlCellValue(excelReader, 6,i));
                issusImagePathVO.setF_DownloadCount(getExlCellValue(excelReader, 7,i));
                //文件创建时间
                issusImagePathVO.setF_CreateUserId(getExlCellValue(excelReader, 9,i));
                issusImagePathVO.setF_CreateUserName(getExlCellValue(excelReader, 10,i));
                issusImagePathVO.setF_DataFileId(getExlCellValue(excelReader, 11,i));
                issusImagePathVO.setF_CompressPath(getExlCellValue(excelReader, 12,i));
                list.add(issusImagePathVO);
            }
            return list;
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            try {
                if (excelReader != null)
                    excelReader.close();
                if (inputStream != null)
                    inputStream.close();
            } catch (Exception e) {
                log.error("Exception occurred while closing stream: {}", ExceptionUtil.stacktraceToString(e));
            }
        }
        return list;
    }

    private IssusLinkPathDTO getIssusLinkPathDTO(IssusImagePathDTO issusImagePathVO,String mid){

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        int random4Digit = (int) (10 + Math.random() * 90);
        String formatted = sdf.format(new Date());
        formatted = formatted+random4Digit;
        long timestamp = Long.parseLong(formatted);

        IssusLinkPathDTO issusLinkPathDTO = new IssusLinkPathDTO();
        issusLinkPathDTO.setMid(mid);
        issusLinkPathDTO.setOid(BigInteger.valueOf(timestamp));
        issusLinkPathDTO.setFilePath(issusImagePathVO.getF_FilePath());
        issusLinkPathDTO.setFileId(issusImagePathVO.getF_Id());
        issusLinkPathDTO.setFileName(issusImagePathVO.getF_FileName());
        issusLinkPathDTO.setCreateUserName(issusImagePathVO.getF_CreateUserName());
        issusLinkPathDTO.setCreateTime(LocalDateTime.now());
        return issusLinkPathDTO;
    }

    private Date parseDate(String dateStr, SimpleDateFormat sdf) {
        // 处理空值、NULL字符串和解析异常
        if (dateStr == null || dateStr.trim().isEmpty() || "NULL".equalsIgnoreCase(dateStr.trim())) {
            return null;
        }
        try {
            return sdf.parse(dateStr.trim());
        } catch (ParseException e) {
            // 可以记录日志，方便排查格式错误的单元格
            log.error("日期解析失败，值: {}, 错误: {}", dateStr, e.getMessage());
            return null;
        }
    }



    public static String getExlCellValue(ExcelReader excelReader, int x, int y) {
        Cell cell = excelReader.getCell(x, y);
        if (cell == null)
            return "";
        CellType cellType = cell.getCellType();
        FormulaEvaluator evaluator = excelReader.getWorkbook().getCreationHelper().createFormulaEvaluator();
        switch (cellType) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getLocalDateTimeCellValue().toString();
                } else {
                    BigDecimal value = BigDecimal.valueOf(cell.getNumericCellValue());
                    value = value.setScale(3, RoundingMode.HALF_UP);
                    return value.toPlainString();
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                // 评估公式并获取结果
                switch (evaluator.evaluate(cell).getCellType()) {
                    case STRING:
                        return evaluator.evaluate(cell).getStringValue();
                    case NUMERIC:
                        return String.valueOf(evaluator.evaluate(cell).getNumberValue());
                    case BOOLEAN:
                        return String.valueOf(evaluator.evaluate(cell).getBooleanValue());
                    default:
                        return "";
                }
            default:
                return "";
        }
    }

    private String buildFormData(PreventErrorCorrectionDO preventErrorCorrectionDO, String formTemplateData) {

        JSONObject formJson = JSONObject.parseObject(formTemplateData);
        // 假设 formJson 是一个 JSONObject 实例，例如使用 Alibaba FastJSON

        formJson.put("ProjectDevelopmentOrder", preventErrorCorrectionDO.getProjectNo());
        formJson.put("ProjectName", null);
        formJson.put("DevelopmentPhase", null);
        formJson.put("ProjectLeader", null);
        formJson.put("Type", preventErrorCorrectionDO.getType());
        formJson.put("ProjectNo", projectCodeGenerator.generateProjectCode());
        formJson.put("TerminalModel", preventErrorCorrectionDO.getTerminalModel());
        formJson.put("PowerModel", preventErrorCorrectionDO.getPowerModel());
        formJson.put("ComponentName",  preventErrorCorrectionDO.getComponentName());
        formJson.put("PatternCode", preventErrorCorrectionDO.getPatternCode());
        formJson.put("OccurrenceDate", preventErrorCorrectionDO.getOccurrenceDate());
        formJson.put("OccurrenceStage", preventErrorCorrectionDO.getOccurrenceStage());
        formJson.put("OccurrenceEnvironment",  preventErrorCorrectionDO.getOccurrenceEnvironment());
        formJson.put("Importance", preventErrorCorrectionDO.getImportance());
        formJson.put("Proposer", TyAccountContext.getUser().getFullname());
        formJson.put("VIN", null);
        formJson.put("PhenomenonDescription", preventErrorCorrectionDO.getPhenomenonDescription());
        //上传图片
        BatchUploadDTO batchUploadDTO=new BatchUploadDTO();
        batchUploadDTO.setRoleKey("RICHTEXTPIC");
        String phenomenonFile = preventErrorCorrectionDO.getPhenomenonFile();
        List<MultipartFile> fileList = this.convert(phenomenonFile);
        batchUploadDTO.setFileList(fileList);
        List<ContentUploadDTO> contentUploadDTOS = this.fileHandleService.batchUploadFile(batchUploadDTO);

        if (CollUtil.isNotEmpty(contentUploadDTOS) && CollUtil.isNotEmpty(fileList)){
            List<Map<String, Object>> maps = assemblePhenomenaPicture(contentUploadDTOS.get(0), fileList.get(0));
            formJson.put("PhenomenaPicture", maps);
        }


        formJson.put("AnalysisDescription", preventErrorCorrectionDO.getAnalysisDescription());
        formJson.put("Attachment", null);
        formJson.put("TentativeCountermeasures", preventErrorCorrectionDO.getTentativeCountermeasures());
        formJson.put("LongCountermeasures", preventErrorCorrectionDO.getLongCountermeasures());
        formJson.put("SourceImprovement", preventErrorCorrectionDO.getSourceImprovement());
        formJson.put("Countermeasures", preventErrorCorrectionDO.getCountermeasure());
        formJson.put("File", null);
        formJson.put("Supplier", preventErrorCorrectionDO.getSupplier());
        formJson.put("ProblemType", preventErrorCorrectionDO.getProblemType());
        formJson.put("ClosingStage", preventErrorCorrectionDO.getClosingStage());
        formJson.put("PersonResponsible", buildUserFormData(preventErrorCorrectionDO.getPersonResponsible()));
        formJson.put("FeedbackDepartment",null);
        formJson.put("FeedbackPerson", buildUserFormData(preventErrorCorrectionDO.getFeedbackPerson()));
        formJson.put("PlannedDate", preventErrorCorrectionDO.getPlannedDate());
        formJson.put("ConfirmationMethod", preventErrorCorrectionDO.getConfirmationMethod());
        formJson.put("ResultAttachment", null);
        formJson.put("ProgressConfirmation", preventErrorCorrectionDO.getProgressConfirmation());
        formJson.put("IsClose", preventErrorCorrectionDO.getIsClose());
        formJson.put("ConfirmDate", preventErrorCorrectionDO.getConfirmDate());
        formJson.put("ConfirmationPerson", buildUserFormData(preventErrorCorrectionDO.getConfirmationPerson()));
        formJson.put("Remark", preventErrorCorrectionDO.getRemark());
        return formJson.toJSONString();
    }

    public JSONObject buildUserFormData(String userName){
        List<UserDO> userDOS = typlmUserService.fuzzyQueryUserForEnabled(userName);
        if(CollUtil.isEmpty(userDOS)){
            return new JSONObject();
        }
        UserDO userDO = userDOS.get(0);
        JSONObject user = new JSONObject();
        user.put("oid", userDO.getOid());
        user.put("otype", userDO.getOtype());
        user.put("fullName", userDO.getFullname());
        user.put("fullNamePinYin", userDO.getFullnamepinyin());
        user.put("namePinYin", userDO.getName());
        user.put("containerOid", userDO.getContaineroid());
        user.put("containerOtype", userDO.getContainerotype());
        user.put("name", userDO.getName());
        user.put("createStamp", userDO.getCreatestamp());
        user.put("rowValue", userDO.getOid());
        return user;
    }


    /**
     * 组装PhenomenaPicture列表
     * @return 组装好的PhenomenaPicture列表
     */
    public  List<Map<String, Object>> assemblePhenomenaPicture(ContentUploadDTO contentUploadDTO,MultipartFile file) {
        // 1. 创建外层列表
        List<Map<String, Object>> phenomenaList = new ArrayList<>();

        // 2. 创建图片主对象
        Map<String, Object> picture = new HashMap<>();
        picture.put("name", file.getName());
        picture.put("percentage", 100); // 固定100%
        picture.put("status", "success"); // 固定成功状态
        picture.put("size", file.getSize());
        BigInteger uid = snowflakeIdComponent.getInstance().nextId();
        picture.put("uid",uid);

        // 3. 组装raw子对象
        Map<String, Object> raw = new HashMap<>();
        raw.put("uid", uid);
        picture.put("raw", raw);

        // 4. 设置URL
        String s = AESUtil.aesEncrypt(contentUploadDTO.getContentId());
        String fileIdStr = AESUtil.base64Encode(s.getBytes(StandardCharsets.UTF_8));

        String url="/rest/v1/fileHandle/downRichTextPicByFileId?fileIdStr="+fileIdStr+"&roleKey=RICHTEXTPIC";
        picture.put("url", url);
        // 5. 组装response子对象
        Map<String, Object> response = new HashMap<>();
        response.put("result", "SUCCESS");
        response.put("success", true);
        response.put("messageBoxIcon", "INFO");
        // 6. 组装response.data子数组
        List<Map<String, Object>> dataList = new ArrayList<>();
        Map<String, Object> data = new HashMap<>();
        data.put("contentId", contentUploadDTO.getContentId());
        data.put("fileName", contentUploadDTO.getFileName());
        data.put("fileSize", ""); // 固定空字符串
        data.put("roleKey", "RICHTEXTPIC"); // 固定角色键
        data.put("streamid", contentUploadDTO.getStreamid());
        data.put("transmissionFileID", ""); // 固定空字符串
        data.put("vaultitemOid", contentUploadDTO.getVaultitemOid());
        dataList.add(data);
        // 7. 拼接response
        response.put("data", dataList);
        picture.put("response", response);
        // 8. 添加到列表
        phenomenaList.add(picture);

        return phenomenaList;
    }


    /**
     * 将Base64图片编码转换为List<MultipartFile>
     * @param base64Str 纯Base64编码字符串（无data:image/xxx;base64,前缀）
     * @return 转换后的MultipartFile列表
     * @throws IOException 解码或IO操作异常
     */
    public  List<MultipartFile> convert(String base64Str) {
        try {
            List<MultipartFile> fileList = new ArrayList<>();
            if (base64Str == null || base64Str.trim().isEmpty()) {
                return fileList;
            }

            // 直接解码Base64（无前缀处理）
            byte[] imageBytes = Base64.getDecoder().decode(base64Str.trim());

            // 生成随机文件名（可根据实际需求指定格式）
            String fileName = UUID.randomUUID()+ ".png"; // 假设为png格式，可根据实际调整

            // 创建MultipartFile对象
            MultipartFile multipartFile = new MockMultipartFile(
                    fileName,         // 表单字段名
                    fileName,       // 文件名
                    "image/png",    // MIME类型
                    new ByteArrayInputStream(imageBytes) // 图片字节流
            );

            fileList.add(multipartFile);
            return fileList;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deletePreventErrorCorrection(PreventErrorCorrectionDTO dto) {
        List<String> objectNumber = dto.getObjectNumber();
        if (objectNumber == null || objectNumber.isEmpty()) {
            throw new IllegalArgumentException("ID 列表不能为空");
        }
        preventErrorCorrectionMapper.deleteBatchByIds(objectNumber);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void startProblemItemTask(StartProblemItemTaskDTO dto) {
        List<ProblemItemDTO> list = dto.getList();
        IdentifierEntity problemItemEntity = new IdentifierEntity();
        problemItemEntity.setOid(new BigInteger(dto.getProblemItemOid()));
        problemItemEntity.setOtype(dto.getProblemItemOtype());
        List<AffectedObjectDTO> objectList = new ArrayList<>();
        if(CollUtil.isNotEmpty(list)){
            for (ProblemItemDTO problemItemDTO : list) {
                String userName = problemItemDTO.getUserName();
                if(StringUtils.isBlank(userName) || StringUtils.isEmpty(userName)){
                    throw RTErrorCodeEnum.USER_NOT_EXIST.getException("任务事项未维护执行人");
                }
                //创建文档
                BigInteger typeOid = typlmTypeService.getTypeOidByName("ProblemHandling");
                Map<String, List<String>> ibaMaps = new HashMap<>();
                ibaMaps.put("Association", Collections.singletonList(dto.getProblemItemOid()));
                ibaMaps.put("AssociationType", Collections.singletonList(dto.getProblemItemOtype()));
                CreateDocInputDTO createDocInputDTO = new CreateDocInputDTO();
                createDocInputDTO.setDocType("ProblemHandling");
                createDocInputDTO.setType(String.valueOf(typeOid));
                createDocInputDTO.setCreator(userName);
                Container container = this.containerService.select(new BigInteger("-1"), TableTypeConstrant.TY_LIBRARY_OTYPE);
                List<SubfolderWebVO> subfolderWebVOS = typlmSubFolderLinkService.querySubFolderListByParent(
                        new BigInteger(container.getDefaultCabinetOid()), container.getDefaultCabinetOtype());
                List<SubfolderWebVO> subfolder = subfolderWebVOS.stream().filter(
                        subfolderWebVO -> subfolderWebVO.getName().equals("问题处理")).collect(
                        Collectors.toList());
                FileGroupDTO fileGroupDTO = new FileGroupDTO();
                fileGroupDTO.setFiles(new ArrayList<>());
                createDocInputDTO.setFolderId(subfolder.get(0).getOid()); // 720353561506643968
                createDocInputDTO.setFolderPath(subfolder.get(0).getFolderPath());
                createDocInputDTO.setContainerType(TableTypeConstrant.TY_LIBRARY_OTYPE);
                createDocInputDTO.setContainerId(container.getOid());
                createDocInputDTO.setProductInfoID(container.getOid());
                createDocInputDTO.setName(problemItemDTO.getTaskName());
                DocumentVO document = docService.createDocument(fileGroupDTO, createDocInputDTO, ibaMaps);
                AffectedObjectDTO affectedObjectDTO = new AffectedObjectDTO();
                IdentifierEntity docEntity = new IdentifierEntity(document.getOid());
                affectedObjectDTO.setOid(docEntity.getOid());
                affectedObjectDTO.setOtype(docEntity.getOtype());
                objectList.add(affectedObjectDTO);
                //启动流程
                createWorkFLow(Collections.singletonList(document), "TEST00", Collections.singletonList(userName));
            }
            if(CollUtil.isNotEmpty(objectList)){
                this.typlmIssueAgainstDataService.batchCreateAffectedLinkList(problemItemEntity, objectList);
            }
        }
    }

    public void createWorkFLow(List<DocumentVO> list, String flowTemplateName, List<String> userNameList) {
        // 处理流对象列表
        List<FlowObject> flowObjectList = dealFlowObjectList(list);
        WorkFlow workFlow = flowControlService.getDefaultWorkFlow(flowTemplateName);
        List<PdmUserDTO> userList = flowControlService.getPdmUserDTOS(userNameList);

        //设置第一个节点的参与者
        BigInteger containerOid = flowObjectList.get(0).getContainerOid();
        String containerOtype = flowObjectList.get(0).getContainerOtype();
        List<UserTaskDTO> allUserTask = typlmWorkFlowContainerService.getAllUserTask(workFlow.getOid(), containerOid, containerOtype);
        if (CollUtil.isNotEmpty(userList)) {
            UserTaskDTO userTaskDTO = allUserTask.get(0);
            userTaskDTO.setUserList(userList);
        }

        String workFlowName = "问题事项_任务接收流程";
        WorkFlowObjectPackage containerView = flowControlService.getWorkFlowContainerView(allUserTask, workFlow, flowObjectList, userList, workFlowName);
        typlmWorkFlowObjectPackageService.insert(containerView);
        this.typlmWorkFlowProcessService.startProcess(containerView, true);
    }

    private List<FlowObject> dealFlowObjectList(List<DocumentVO> documentVOS) {
        List<FlowObject> flowObjectList = new ArrayList<>();
        for (DocumentVO documentVO : documentVOS) {
            FlowObject flowObject = new FlowObject();
            flowObject.setRefObjectOid(new BigInteger(documentVO.getOid().split(":")[1]));
            flowObject.setVersion(documentVO.getVersion());
            flowObject.setRefObjectOtype(documentVO.getOtype());
            flowObject.setRefObjectNumber(documentVO.getDocnumber());
            flowObject.setRefObjectName(documentVO.getName());
            flowObject.setBranchId(documentVO.getBranchid());
            flowObject.setMasteredoid(new BigInteger(documentVO.getMasteredoid()));
            flowObject.setContainerOid(documentVO.getContaineroid());
            flowObject.setContainerOtype(documentVO.getContainerotype());
            flowObjectList.add(flowObject);
        }
        log.info("流程对象============>flowObjectList:{}", flowObjectList);
        return flowObjectList;
    }

    @Override
    public String selectProjectOrderByProjectId(String projectId) {
        return preventErrorCorrectionMapper.selectProjectOrderByProjectId(projectId);
    }

    @Override
    public List<String> getAllProjectNo() {
        return preventErrorCorrectionMapper.getAllProjectNo();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createFileAndProblemItemLink(BigInteger workFlowContainerId) throws  Exception{
        WorkFlowContainerView workFlowContainerView = typlmWorkFlowContainerService.getWorkFlowContainerDetailByPrimaryKey(
                workFlowContainerId);
        List<IdentifierEntity> flowObjEntityList = commonService.getFlowObjListByWorkFlowContainer(workFlowContainerView);
        List<IdentifierEntity> docEntityList = flowObjEntityList.stream()
                .filter(identifierEntity -> TableTypeConstrant.TY_DOC_OTYPE.equals(identifierEntity.getOtype()))
                .collect(Collectors.toList());
        if(CollUtil.isEmpty(docEntityList)){
            return;
        }
        List<BigInteger> docOidList = docEntityList.stream().map(IdentifierEntity::getOid).collect(Collectors.toList());
        List<String> ibaAttr = Arrays.asList("Association","AssociationType");
        Map<String, List<AttributeVO>> docIbaMap = typlmAttributeValueService.getIbaAttrValueByOidAndKeys(
                docOidList,
                TableTypeConstrant.TY_DOC_OTYPE,
                ibaAttr
                );
        Map<IdentifierEntity, List<FileDataVO>> identifierEntityListMap = fileHandleService.batchGetFileListByEntity(
                docEntityList);
        for (IdentifierEntity entity : docEntityList) {
            BigInteger oid = entity.getOid();
            if(!docIbaMap.containsKey(String.valueOf(oid))){
                continue;
            }
            List<AttributeVO> attributeVOList = docIbaMap.get(String.valueOf(oid));
            String problemItemOid = "";
            String problemItemType = "";
            for (AttributeVO attributeVO : attributeVOList) {
                if ("Association".equals(attributeVO.getAttributeEnName())) {
                    problemItemOid = StringUtils.isBlank(attributeVO.getAttributeValuex()) ? attributeVO.getAttributeValue()
                            : attributeVO.getAttributeValuex();
                } else if ("AssociationType".equals(attributeVO.getAttributeEnName())) {
                    problemItemType = StringUtils.isBlank(attributeVO.getAttributeValuex()) ? attributeVO.getAttributeValue()
                            : attributeVO.getAttributeValuex();

                }
            }
            if(StringUtils.isBlank(problemItemOid) || StringUtils.isBlank(problemItemType) || StringUtils.isEmpty(problemItemType) || StringUtils.isEmpty(problemItemOid)){
                continue;
            }
            List<BigInteger> fileIds = new ArrayList<>();
            if(identifierEntityListMap.containsKey(entity)){
                List<FileDataVO> fileDataVOList = identifierEntityListMap.get(entity);
                if(CollUtil.isNotEmpty(fileDataVOList)){
                    for (FileDataVO fileDataVO : fileDataVOList) {
                        fileIds.add(new BigInteger(fileDataVO.getFileID()));
                    }
                }
            }
            if (CollUtil.isNotEmpty(fileIds)) {
                List<CadDownloadFileVO> cadDownloadFileVOList = this.typlmFileTransferService.getDownloadFileDTOS(fileIds,
                                                                                                                  TyAccountContext.getUser()
                                                                                                                          .getOid());
                List<DownloadFileDTO> downloadFileDTOList = TyplmDownloadToolUtil.getDownloadFileDTOS(cadDownloadFileVOList);
                List<MultipartFile> fileList = new ArrayList<>();
                for (DownloadFileDTO downloadFileDTO : downloadFileDTOList) {
                    this.typlmEncryptService.recordFileNameKeys(new BigInteger(downloadFileDTO.getFileId()));
                    DownLoadFileVO downLoadFileVO = this.typlmContentDataService.getInputStream(downloadFileDTO);
                    String fileName = downLoadFileVO.getFileName();
                    File file = downLoadFileVO.getFile();
                    MultipartFile mockMultipartFile = new MockMultipartFile(fileName, fileName,
                                                                            "application/octet-stream",
                                                                            Files.newInputStream(file.toPath()));
                    fileList.add(mockMultipartFile);
                }
                addFileToAttachment(fileList, problemItemType, problemItemOid);
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertPreventErrorCorrection(List<PreventErrorCorrectionDO> prevenList) {
        //创建问题报告
        try {
            BigInteger noticeTypeOid = typlmTypeService.getTypeOidByName("Issue");
            TyplmBaseRuleBoundedObjDTO info = this.typlmBasedRuleService.getBaseRuleBoundedObjInfo(
                    noticeTypeOid, prevenList.get(0).getOid(), TableTypeConstrant.TY_PROJECT_TYPE);

            TyplmSegmentCodeConditionDTO param = new TyplmSegmentCodeConditionDTO();
            param.setOtype(TableTypeConstrant.TY_CHANGEISSUE_OTYPE);
            param.setRuleInfo(new IdentifierEntity(info.getSegmentCodeOid(), info.getSegmentCodeOtype()));

            BigInteger projectOid = prevenList.get(0).getOid();
            String url =  ipdUrl + "/api/v1/dashboard/getProjectDetailByOID";
            UriComponentsBuilder urlBuilder = UriComponentsBuilder.fromHttpUrl(url)
                    .queryParam("oid", projectOid);
            String responseData = commonService.sendGetRequestToIPD(urlBuilder.toUriString());
            log.info("项目信息=========>: {}", responseData);
            JSONObject responseJson = JSONObject.parseObject(responseData);
            JSONObject data = responseJson.getJSONObject("data");
            String projectType = data.getString("category");
            String projectNumber = "";
            String productType = "";

            // 处理 productType（增加 JSON 字段存在性判断，避免异常）
            JSONObject ibaAttribute = data.getJSONObject("ibaAttribute");
            if (CollUtil.isNotEmpty(ibaAttribute) && ibaAttribute.containsKey("productType")) {
                JSONArray jsonArray = ibaAttribute.getJSONArray("productType");
                if (CollUtil.isNotEmpty(jsonArray)) {
                    productType = jsonArray.getString(0);
                }
            }
            if (CollUtil.isNotEmpty(ibaAttribute) && ibaAttribute.containsKey("ProjectDevelopmentOrder")) {
                JSONArray jsonArray = ibaAttribute.getJSONArray("ProjectDevelopmentOrder");
                if (CollUtil.isNotEmpty(jsonArray)) {
                    projectNumber = jsonArray.getString(0);
                }
            }

            // 校验项目类型
            Set<String> typeSet = prevenList.stream().map(PreventErrorCorrectionDO::getType).collect(Collectors.toSet());
            validateSingleValue(
                    typeSet,
                    projectType,
                    "类型为空不允许导入",
                    "请选择同一类型",
                    "项目类型与当前项目不一致不允许导入"
            );

            // 校验项目编号（修正变量混淆问题）
            Set<String> projectNoSet = prevenList.stream().map(PreventErrorCorrectionDO::getProjectNo).collect(Collectors.toSet());
            validateSingleValue(
                    projectNoSet,
                    projectNumber,
                    "项目编号为空不允许导入",
                    "请选择同一编号的项目导入",
                    "项目编号与当前项目不一致不允许导入"
            );

            // 校验机型（修正变量混淆问题）
            Set<String> terminalModelSet = prevenList.stream().map(PreventErrorCorrectionDO::getTerminalModel).collect(Collectors.toSet());
            validateSingleValue(
                    terminalModelSet,
                    productType,
                    "项目机型为空不允许导入",
                    "请选择同一机型的项目导入",
                    "机型与当前项目不一致不允许导入"
            );

            String formTemplateData = formTemplateMapper.queryTemplateDataByOid(info.getFormTemplateOid());
            for (PreventErrorCorrectionDO preventErrorCorrectionDO : prevenList) {
                TyplmChangeIssueDTO changeIssueDTO = new TyplmChangeIssueDTO();
                TyplmSegmentCodeRuleVO codeData = this.typlmSegmentCodeService.getSegmentFormData(param);
                changeIssueDTO.setName(codeData.getCode()+"-"+"问题报告");
                changeIssueDTO.setContaineroid(preventErrorCorrectionDO.getOid());
                changeIssueDTO.setContainerotype(TableTypeConstrant.TY_PROJECT_TYPE);

                changeIssueDTO.setTypeoid(noticeTypeOid);

                changeIssueDTO.setObjectNumber(codeData.getCode());
                changeIssueDTO.setFormtemplateoid(info.getFormTemplateOid());
                changeIssueDTO.setFormtemplateotype(info.getFormTemplateOtype());

                changeIssueDTO.setFormData(buildFormData(preventErrorCorrectionDO,formTemplateData));
                changeIssueDTO.setIssuepriority(RTPlmConstant.NORMAL);
                List<TyplmChangeIssueDetailDTO> changeIssue = typlmChangeIssueService.createChangeIssueAndEcLink(changeIssueDTO);

                preventErrorCorrectionDO.setChangeIssueCode(changeIssueDTO.getObjectNumber());
                CreatIssueLinkDTO creatIssueLink = new CreatIssueLinkDTO();
                creatIssueLink.setLocalRepositoryUid("javaPDM");
                creatIssueLink.setProjectOid(preventErrorCorrectionDO.getOid().toString());
                creatIssueLink.setProjectOtype(TableTypeConstrant.TY_PROJECT_TYPE);
                List<JSONObject> objectList = JSON.parseArray(JSON.toJSONString(changeIssue), JSONObject.class);
                creatIssueLink.setObjectList(objectList);

                // 构建请求头
                HttpHeaders headers = new HttpHeaders();
                // 设置认证令牌
                headers.set(HttpHeaders.AUTHORIZATION, TyAccountContext.getToken());
                // 设置内容类型为JSON
                headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
                // 封装请求实体（请求体为CreatIssueLinkDTO，请求头为上述设置）
                HttpEntity<CreatIssueLinkDTO> requestEntity = new HttpEntity<>(creatIssueLink, headers);
                restTemplate.exchange(
                        mainServiceUrl,  // 完整接口地址
                        HttpMethod.POST,                                // 请求方法
                        requestEntity,                                  // 请求实体
                        new ParameterizedTypeReference<Void>() {}
                );

                log.info("{}","生成成功！");

                //上传视频附件
                if (CollUtil.isNotEmpty(preventErrorCorrectionDO.getFile())) {
                    BatchUploadDTO batchUploadDTO=new BatchUploadDTO();
                    batchUploadDTO.setOid(changeIssue.get(0).getOid().toString());
                    batchUploadDTO.setOtype(TableTypeConstrant.TY_CHANGEISSUE_OTYPE);
                    preventErrorCorrectionDO.setVideoFile(preventErrorCorrectionDO.getFile().get(0));
                    List<MultipartFile> fileList = new ArrayList<>();
                    for (String file : preventErrorCorrectionDO.getFile()) {
                        MultipartFile multipartFile = Base64ToMultipartFileUtil.convert(file);
                        fileList.add(multipartFile);
                    }
                    batchUploadDTO.setFileList(fileList);
                    fileHandleService.batchUploadFile(batchUploadDTO);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("创建问题报告失败:{}", e.getMessage());
            throw RTErrorCodeEnum.PROJECT_DEV_ORDER.getException(e.getMessage());
        }
        preventErrorCorrectionMapper.batchInsertPrevent(prevenList);
    }

    // 提取通用校验方法：校验集合是否唯一、非空，并与目标值匹配
    private void validateSingleValue(Set<String> valueSet, String targetValue,
                                     String notEmptyMsg, String notSingleMsg, String notMatchMsg) {
        if (CollUtil.isEmpty(valueSet)) {
            throw RTErrorCodeEnum.PROJECT_DEV_ORDER.getException(notEmptyMsg);
        }
        if (valueSet.size() > 1) {
            throw RTErrorCodeEnum.PROJECT_DEV_ORDER.getException(notSingleMsg);
        }
        String actualValue = valueSet.iterator().next();
        if (StringUtils.isNotBlank(targetValue) && !targetValue.equals(actualValue)) {
            throw RTErrorCodeEnum.PROJECT_DEV_ORDER.getException(notMatchMsg);
        }
        if (StringUtils.isBlank(targetValue)) {
            throw RTErrorCodeEnum.PROJECT_DEV_ORDER.getException("当前" + notEmptyMsg.replace("不允许导入", "为空不允许导入"));
        }
    }

    @Override
    public PageInfo<PreventErrorCorrectionDO> getPreventErrorCorrection(int pageNum,int pageSize,String projectId) {

        List<PreventErrorCorrectionDO> list=null;
        if (StringUtils.isNotBlank(projectId)){
            String order = preventErrorCorrectionMapper.selectProjectOrderByProjectId(projectId);
            PageHelper.startPage(pageNum, pageSize);
            if (StrUtil.isNotBlank(order)){
                list = preventErrorCorrectionMapper.selectAll(order);
            }else {
                list = preventErrorCorrectionMapper.selectAll(null);
            }
        }else {
            PageHelper.startPage(pageNum, pageSize);
            list = preventErrorCorrectionMapper.selectAll(null);
        }
        return new PageInfo<>(list);

    }

    @Override
    public void insertPreventCorrectionFromProblem(List<PreventErrorCorrectionDO> prevenList) {
        try {
            ContainerCommonQueryVO container = containerAndFolderService.getContainerByName(
                    RTPlmConstant.PRODUCT_CONTAINER_NAME);
            BigInteger noticeTypeOid = typlmTypeService.getTypeOidByName("问题");
            BigInteger containerId = new BigInteger(container.getId());
            TyplmBaseRuleBoundedObjDTO info = this.typlmBasedRuleService.getBaseRuleBoundedObjInfo(
                    noticeTypeOid, containerId, container.getOtype());
            TyplmSegmentCodeConditionDTO param = new TyplmSegmentCodeConditionDTO();
            param.setOtype(TableTypeConstrant.TY_CHANGEISSUE_OTYPE);
            param.setRuleInfo(new IdentifierEntity(info.getSegmentCodeOid(), info.getSegmentCodeOtype()));

            BigInteger subFolderOid = containerAndFolderMapper.getOIDByNameAndContainerOid(
                    RTPlmConstant.PROBLEM_REPORT, containerId);
            String formTemplateData = formTemplateMapper.queryTemplateDataByOid(info.getFormTemplateOid());
            for (PreventErrorCorrectionDO preventErrorCorrectionDO : prevenList) {
                TyplmSegmentCodeRuleVO codeData = this.typlmSegmentCodeService.getSegmentFormData(param);
                TyplmChangeIssueDTO changeIssueDTO = new TyplmChangeIssueDTO();
                changeIssueDTO.setName(RTPlmConstant.PROBLEM_REPORT);
                changeIssueDTO.setContaineroid(containerId);
                changeIssueDTO.setContainerotype(container.getOtype());
                changeIssueDTO.setSubfolderoid(subFolderOid);
                changeIssueDTO.setTypeoid(noticeTypeOid);

                changeIssueDTO.setObjectNumber(codeData.getCode());
                changeIssueDTO.setFormtemplateoid(info.getFormTemplateOid());
                changeIssueDTO.setFormtemplateotype(info.getFormTemplateOtype());


                changeIssueDTO.setFormData(buildFormData(preventErrorCorrectionDO, formTemplateData));
                changeIssueDTO.setIssuepriority(RTPlmConstant.NORMAL);
                List<TyplmChangeIssueDetailDTO> changeIssue = typlmChangeIssueService.createChangeIssueAndEcLink(changeIssueDTO);

                //上传视频附件
                if (CollUtil.isNotEmpty(preventErrorCorrectionDO.getFile())) {
                    BatchUploadDTO batchUploadDTO=new BatchUploadDTO();
                    batchUploadDTO.setOid(changeIssue.get(0).getOid().toString());
                    batchUploadDTO.setOtype(TableTypeConstrant.TY_CHANGEISSUE_OTYPE);
                    preventErrorCorrectionDO.setVideoFile(preventErrorCorrectionDO.getFile().get(0));
                    List<MultipartFile> fileList = new ArrayList<>();
                    for (String file : preventErrorCorrectionDO.getFile()) {
                        MultipartFile multipartFile = Base64ToMultipartFileUtil.convert(file);
                        fileList.add(multipartFile);
                    }
                    batchUploadDTO.setFileList(fileList);
                    fileHandleService.batchUploadFile(batchUploadDTO);
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("创建问题报告失败:{}", e.getMessage());

        }
        preventErrorCorrectionMapper.batchInsertPrevent(prevenList);
    }

    private void addFileToAttachment(List<MultipartFile> fileList, String otype, String oid) {
        UserDO user = TyAccountContext.getUser();
        BatchUploadDTO batchUploadDTO = new BatchUploadDTO();
        batchUploadDTO.setInsertFlag(true);
        batchUploadDTO.setUpdatoroid(user.getOid());
        batchUploadDTO.setUpdatorotype(user.getUsertype());
        batchUploadDTO.setOid(oid);
        batchUploadDTO.setOtype(otype);
        batchUploadDTO.setFileList(fileList);
        this.fileHandleService.batchUploadFile(batchUploadDTO);
    }
}
